package main

import (
	"encoding/csv"
	"encoding/xml"
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
)

type Xml struct {
	XMLName      xml.Name `xml:"xml"`
	Text         string   `xml:",chardata"`
	Dictionaries struct {
		Text   string `xml:",chardata"`
		Fields struct {
			Text string `xml:",chardata"`
			Item []struct {
				Text     string `xml:",chardata"`
				Code     string `xml:"code,attr"`
				Type     string `xml:"type,attr"`
				Multiple string `xml:"multiple,attr"`
			} `xml:"item"`
		} `xml:"fields"`
		Countries struct {
			Text string `xml:",chardata"`
			Item []struct {
				Text string `xml:",chardata"`
				Code string `xml:"code,attr"`
			} `xml:"item"`
		} `xml:"countries"`
		CodesOkpd struct {
			Text string `xml:",chardata"`
			Item []struct {
				Text string `xml:",chardata"`
				Code string `xml:"code,attr"`
			} `xml:"item"`
		} `xml:"codesOkpd"`
		SoftwareClasses struct {
			Text        string `xml:",chardata"`
			Classifiers struct {
				Text       string `xml:",chardata"`
				Classifier []struct {
					Text   string `xml:",chardata"`
					Date   string `xml:"date,attr"`
					DocNum string `xml:"docNum,attr"`
				} `xml:"classifier"`
			} `xml:"classifiers"`
			Items struct {
				Text string `xml:",chardata"`
				Item []struct {
					Text       string `xml:",chardata"`
					Code       string `xml:"code,attr"`
					Classifier string `xml:"classifier,attr"`
				} `xml:"item"`
			} `xml:"items"`
		} `xml:"softwareClasses"`
	} `xml:"dictionaries"`
	Registry struct {
		Text    string `xml:",chardata"`
		Name    string `xml:"name,attr"`
		GenDate string `xml:"genDate,attr"`
		Item    []struct {
			Text                    string   `xml:",chardata"`
			ID                      string   `xml:"id,attr"`
			RegistrationNumber      string   `xml:"registrationNumber"`
			Name                    string   `xml:"name"`
			PreviousAlternativeName []string `xml:"previousAlternativeName"`
			Owner                   []struct {
				Text   string `xml:",chardata"`
				Status struct {
					Text string `xml:",chardata"`
					Code string `xml:"code,attr"`
				} `xml:"status"`
				Name struct {
					Text       string `xml:",chardata"`
					LastName   string `xml:"lastName,attr"`
					FirstName  string `xml:"firstName,attr"`
					Patronymic string `xml:"patronymic,attr"`
				} `xml:"name"`
				ShortName            string `xml:"shortName"`
				CountryCode          string `xml:"countryCode"`
				IdentificationNumber struct {
					Text string `xml:",chardata"`
					Type string `xml:"type,attr"`
				} `xml:"identificationNumber"`
				MainStateRegistrationNumber string `xml:"mainStateRegistrationNumber"`
				Representative              struct {
					Text string `xml:",chardata"`
					Type struct {
						Text string `xml:",chardata"`
						Code string `xml:"code,attr"`
					} `xml:"type"`
					Name                 string `xml:"name"`
					ShortName            string `xml:"shortName"`
					IdentificationNumber struct {
						Text string `xml:",chardata"`
						Type string `xml:"type,attr"`
					} `xml:"identificationNumber"`
					MainStateRegistrationNumber string `xml:"mainStateRegistrationNumber"`
				} `xml:"representative"`
			} `xml:"owner"`
			ExclusiveRight                                         string `xml:"exclusiveRight"`
			InformationInAlgorithmsAndComputerProgramsNationalFund string `xml:"informationInAlgorithmsAndComputerProgramsNationalFund"`
			SupportUsersWithHearingImpairments                     string `xml:"supportUsersWithHearingImpairments"`
			SupportUsersWithVisualImpairments                      string `xml:"supportUsersWithVisualImpairments"`
			DescriptionLink                                        string `xml:"descriptionLink"`
			CostLink                                               string `xml:"costLink"`
			CodeOkpd                                               []struct {
				Text string `xml:",chardata"`
				Code string `xml:"code,attr"`
			} `xml:"codeOkpd"`
			SoftwareClass []struct {
				Text       string `xml:",chardata"`
				Code       string `xml:"code,attr"`
				Main       string `xml:"main,attr"`
				Classifier string `xml:"classifier,attr"`
			} `xml:"softwareClass"`
			CompliancePP325            string `xml:"compliancePP325"`
			GosRegistrationNumber      string `xml:"gosRegistrationNumber"`
			GosRegistrationDate        string `xml:"gosRegistrationDate"`
			InclusionApplicationDate   string `xml:"inclusionApplicationDate"`
			InclusionApplicationNumber string `xml:"inclusionApplicationNumber"`
			InclusionDate              string `xml:"inclusionDate"`
			InclusionNumber            string `xml:"inclusionNumber"`
			InclusionType              string `xml:"inclusionType"`
			Excluded                   string `xml:"excluded"`
			ExclusionApplicationDate   string `xml:"exclusionApplicationDate"`
			ExclusionApplicationNumber string `xml:"exclusionApplicationNumber"`
			ExclusionDate              string `xml:"exclusionDate"`
			ExclusionNumber            string `xml:"exclusionNumber"`
			ExclusionType              string `xml:"exclusionType"`
			Module                     []struct {
				Text string `xml:",chardata"`
				Name string `xml:"name"`
			} `xml:"module"`
			ItIsModuleOfAnotherSoftwareInRegistry string `xml:"itIsModuleOfAnotherSoftwareInRegistry"`
			EditHistory                           []struct {
				Text      string `xml:",chardata"`
				ID        string `xml:"id,attr"`
				Date      string `xml:"date,attr"`
				Timestamp string `xml:"timestamp,attr"`
				Type      string `xml:"type,attr"`
				Field     []struct {
					Text string `xml:",chardata"`
					Code string `xml:"code,attr"`
					Name string `xml:"name"`
					Old  string `xml:"old"`
					New  string `xml:"new"`
				} `xml:"field"`
			} `xml:"editHistory"`
		} `xml:"item"`
	} `xml:"registry"`
}

type softwareListFinal struct {
	softRegNumber string
	softName      string
	softAltName   string
	softCode      string
	softLink      string
	softType      string
}

func downloadFile(url string, filepath string) error {
	client := &http.Client{
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return nil
		},
	}

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return err
	}

	// Добавляем заголовок User-Agent
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")

	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("ошибка загрузки файла: %s", resp.Status)
	}

	out, err := os.Create(filepath)
	if err != nil {
		return err
	}
	defer out.Close()

	_, err = io.Copy(out, resp.Body)
	if err != nil {
		return err
	}

	return nil
}

// Функция для определения типа ПО на основе словаря
func determineSoftwareType(str string) string {
	var trigWordMap = map[string]string{
		"судопроход":     "Не подходит",
		"школа":          "Не подходит",
		"нефт":           "Подходит",
		"электроэнергия": "Подходит",
		"энерго":         "Подходит",
		"ЭНЕРГО":         "Подходит",
		"энергетика":     "Подходит",
		"электротехника": "Подходит",
	}
	for k, v := range trigWordMap {
		if strings.Contains(str, k) {
			return v

		}
	}
	return "Не известно"
}

func handleXMLFile(xmlFileName string) {

	xmlFile, err := os.Open(xmlFileName)
	if err != nil {
		fmt.Printf("Ошибка при открытии файла: %v\n", err)
		return
	}
	defer xmlFile.Close()

	var regData Xml
	var finalData []softwareListFinal
	decoder := xml.NewDecoder(xmlFile)
	err = decoder.Decode(&regData)
	if err != nil {
		fmt.Printf("Ошибка при декодировании XML: %v\n", err)
		return
	}
	var codeMap map[string]string
	codeMap = make(map[string]string)
	for _, item := range regData.Dictionaries.SoftwareClasses.Items.Item {
		codeMap[item.Code] = item.Text
	}
	for _, item := range regData.Registry.Item {
		iData := softwareListFinal{
			softRegNumber: item.RegistrationNumber,
			softName:      item.Name,
			softLink:      item.DescriptionLink,
			softType:      determineSoftwareType(item.Name),
		}
		for _, prName := range item.PreviousAlternativeName {
			iData.softAltName = iData.softAltName + " \n" + prName
			r := determineSoftwareType(prName)
			if r != "Не известно" {
				iData.softType = r
				break
			}
		}
		for _, code := range item.SoftwareClass {
			softCode := codeMap[code.Code]
			iData.softCode = iData.softCode + "\n" + code.Code + " " + softCode
		}
		finalData = append(finalData, iData)
	}
	csvFilename := "software_list.csv"
	csvFile, err := os.Create(csvFilename)
	if err != nil {
		fmt.Printf("Ошибка при создании CSV файла: %v\n", err)
		return
	}
	defer csvFile.Close()

	writer := csv.NewWriter(csvFile)
	defer writer.Flush()

	// Заголовки CSV файла
	headers := []string{"Регистрационный номер", "Наименование ПО", "Альтернативное название ПО", "Код продукции", "Ссылка", "Type"}
	err = writer.Write(headers)
	if err != nil {
		fmt.Printf("Ошибка при записи заголовков в CSV: %v\n", err)
		return
	}

	// Запись данных в CSV файл
	for _, item := range finalData {
		row := []string{item.softRegNumber, item.softName, item.softAltName, item.softCode, item.softLink, item.softType}
		err := writer.Write(row)
		if err != nil {
			fmt.Printf("Ошибка при записи строки в CSV: %v\n", err)
			return
		}
	}

	fmt.Printf("Данные успешно записаны в файл: %s\n", csvFilename)
	os.Remove(xmlFileName) // delete xmlFile

}

func main() {
	url := "https://reestr.digital.gov.ru/reestr/?export=registry"
	filepath := "downloaded_registry.xml"

	err := downloadFile(url, filepath)
	if err != nil {
		fmt.Printf("Ошибка при скачивании файла: %v\n", err)
	} else {
		fmt.Println("Файл успешно скачан и сохранен как", filepath)
	}
	handleXMLFile(filepath)
}
